#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include "yemu.h"
#include "../image/build/Image.h"

uint64_t InstFreq[InstCnt] = {0};
void InstStatistics();

int main() {
    
    uint32_t Inst;
    struct ARCHINFO ArchInfo;
    struct INSTINFO InstInfo;
    
    Logo();
    Reset(&ArchInfo);
    
    while(1) {
        Inst = InstFetch(ArchInfo);
        // printf("inst = 0x%08x\n", Inst);
        InstInfo = InstDecode(Inst);
        ArchInfo = Execute(ArchInfo, InstInfo);
        InstFreq[InstInfo.InstKind]++;
        if(Inst == 0x6F) break;
    }
    
    Halt(&ArchInfo);
    // InstStatistics();
    return 0;
}

void Reset(struct ARCHINFO* ArchInfo) {
    ArchInfo->PC = 0x80000000;
    ArchInfo->Mcycle = 0;
    for (int i = 0; i < 32; i++) ArchInfo->Regs[i] = 0;
    ArchInfo->Mem = (unsigned char*)malloc(MEM_SIZE);
    for (unsigned int i = 0; i < Image_len; i++) ArchInfo->Mem[MEM_OFFSET + i] = Image[i];
    return ;
}

void Halt(struct ARCHINFO* ArchInfo) {
    free(ArchInfo->Mem);
    printf(COLOR_GREEN "Yemu end at a0 = %lld\n" COLOR_RESET, ArchInfo->Regs[a0]);
    // if(ArchInfo->Regs[a0] == 0) 
    //     printf(COLOR_GREEN "Hit Good Trap, PC = %08llx, Mcycle = %llu\n" COLOR_RESET, ArchInfo->PC, ArchInfo->Mcycle);
    // else 
    //     printf(COLOR_RED "Hit Good Trap, PC = %08llx, Mcycle = %llu\n" COLOR_RESET, ArchInfo->PC, ArchInfo->Mcycle);
    return ;
}

void InstStatistics() {
    const char* InstName[InstCnt] = {
        "ILL",
        "LUI", "AUIPC",      
        "SLT", "SLTI", "SLTU", "SLTIU",
        "OR", "AND", "XOR", "ORI", "ANDI", "XORI", 
        "ADD", "ADDI", "ADDW", "ADDIW", "SUB", "SUBW",
        "BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU", "JAL", "JALR", 
        "LB", "LH", "LW", "LD", "LBU", "LHU", "LWU", "SB", "SH", "SW", "SD", 
        "SLL", "SRL", "SRA", "SLLI", "SRLI", "SRAI", "SLLW", "SRLW", "SRAW", "SLLIW", "SRLIW", "SRAIW",
    };
    printf("---- Instruction Frequency ----\n");
    for (int i = 0; i < InstCnt; i++) {
        if(InstFreq[i] > 0)
            printf("%-8s: %llu\n", InstName[i], InstFreq[i]);
    }
    printf("------------------------------\n");
    return ;
}

void Logo() {
    printf("\n");
    printf(" __     ________ __  __ _    _ \n");
    printf(" \\ \\   / /  ____|  \\/  | |  | |\n");
    printf("  \\ \\_/ /| |__  | \\  / | |  | |\n");
    printf("   \\   / |  __| | |\\/| | |  | |\n");
    printf("    | |  | |____| |  | | |__| |\n");
    printf("    |_|  |______|_|  |_|\\____/ \n");
    printf("\n");
    return ;
}
